/*
** display.c for Kernel in /home/icecrime/Kernel
** 
** Made by U-ICE\icecrime
** Login   <icecrime@epita.fr>
** 
** Started on  Tue Oct 17 18:20:09 2006 U-ICE\icecrime
** Last update Thu Oct 19 17:36:37 2006 icecrime
*/

#include "assert.h"
#include "system.h"
#include "display.h"

#define TAB_SIZE	(8)
#define TEXT_VID	((uint16 *)0xB8000)
#define SCR_WIDTH	(80)
#define SCR_HEIGHT	(25)
#define SCR_SIZE	(SCR_WIDTH * SCR_HEIGHT)

#define DFT_ATTRIB	(0X07)
#define DFT_CLEAR_CHAR	('\0')

static uint32	gl_current_idx = 0;

static void	__scroll_buff(void);

void		cls(void)
{
  clsp('\0', DFT_ATTRIB);
}

void		clsp(char clear_to, char attrib)
{
  int		pos;
  int		size;
  uint16	*text_vid;

  pos = 0;
  gl_current_idx = 0;
  size = SCR_WIDTH * SCR_HEIGHT;
  text_vid = (uint16 *)TEXT_VID;
  while (pos < size)
    {
      *text_vid = clear_to | (attrib << 8);
      text_vid++;
      pos++;
    }
  gl_current_idx = 0;
}

void		putch(const char c)
{
  putchp(c, DFT_ATTRIB);
}

void		putchp(const char c, char attrib)
{
  switch (c)
    {
    case '\r':
      gl_current_idx -= gl_current_idx % SCR_WIDTH;
      break;
    case '\t':
      gl_current_idx += TAB_SIZE;
      break;
    case '\n':
      gl_current_idx += SCR_WIDTH - (gl_current_idx % SCR_WIDTH);
      break;
    default:
      if (gl_current_idx == SCR_SIZE)
	{
	  __scroll_buff();
	  gl_current_idx = 0;
	  return;
	}
      TEXT_VID[gl_current_idx] = c | (attrib << 8);
      gl_current_idx++;
      break;
    }
}

void		puts(const char *str)
{
  assert(str != NULL, "Argument to puts should not be null.");
  putsp(str, DFT_ATTRIB);
}

void		putsp(const char *str, char attrib)
{
  assert(str != NULL, "Argument to putsp should not be null.");
  while (*str != NULL)
    {
      putchp(*str, attrib);
      str++;
    }
}

void		putnumber(const int number)
{
  putnumberp(number, DFT_ATTRIB);
}

void		putnumberp(const int number, char attrib)
{
  int32		d;
  int32		n;

  d = 1;
  n = number;
  if (number < 0)
    {
      n *= -1;
      putchp('-', attrib);
    }
  while (n / d >= 10)
    d *= 10;
  for (; d > 0; d /= 10)
    putchp('0' + (n / d) % 10, attrib);
}

static void	__scroll_buff(void)
{
  int		i;
  int		size;
  uint16	*text_vid;
  uint16	*text_vid2;

  text_vid = TEXT_VID;
  text_vid2 = TEXT_VID + SCR_WIDTH;
  size = SCR_SIZE - SCR_WIDTH;
  for (i = 0; i < size; ++i)
    {
      *text_vid = *text_vid2;
      text_vid++;
      text_vid2++;
    }
  for (i = 0; i < SCR_WIDTH; ++i)
    {
      *text_vid = DFT_CLEAR_CHAR | DFT_ATTRIB << 8;
      text_vid++;
    }
}
